using System;
using System.Text;
using Oracle.ManagedDataAccess.Types;

namespace OracleInternal.ServiceObjects
{
	internal class OracleXmlStreamImpl
	{
		internal object m_syncLock = new object();

		internal OracleConnectionImpl m_connImpl;

		internal OraXmlTypeData m_xmlTypeData;

		internal OracleXmlTypeImpl m_xmlTypeImplObj;

		private long m_streamDataLength = -1L;

		internal string m_xmlStr;

		internal char[] m_xmlChars;

		internal OracleClob m_xmlClob;

		internal StringBuilder m_xmlBlobText;

		internal int m_oddByteValue = -1;

		internal TypeOfXmlData m_xmlStreamType = TypeOfXmlData.String;

		private bool m_bInitialized;

		private OracleXmlStreamImpl()
		{
		}

		internal OracleXmlStreamImpl(OracleConnectionImpl connImpl, OracleXmlTypeImpl xmlTypeImplObj)
		{
			m_connImpl = connImpl;
			m_xmlTypeImplObj = xmlTypeImplObj;
			m_xmlTypeData = xmlTypeImplObj.m_xmlTypeData;
			if (!m_bInitialized)
			{
				Initialize();
			}
		}

		private void Initialize()
		{
			m_bInitialized = true;
			switch (m_xmlTypeData.m_typeOfXmlData)
			{
			case TypeOfXmlData.String:
			case TypeOfXmlData.ClobAndString:
			case TypeOfXmlData.XmlDoc:
			case TypeOfXmlData.StringAndXmlDoc:
				m_xmlStr = m_xmlTypeData.m_xmlStr;
				m_xmlStreamType = TypeOfXmlData.String;
				break;
			case TypeOfXmlData.Chars:
				m_xmlChars = m_xmlTypeData.m_xmlChars;
				m_xmlStreamType = TypeOfXmlData.Chars;
				break;
			case TypeOfXmlData.Clob:
				m_xmlClob = (OracleClob)m_xmlTypeData.m_xmlClob.Clone();
				m_xmlStreamType = TypeOfXmlData.Clob;
				break;
			case TypeOfXmlData.BlobCSX:
			case TypeOfXmlData.BlobCSXAndString:
				m_xmlBlobText = m_xmlTypeImplObj.GetBinXmlDecodedStringBuilder(m_xmlTypeData.m_xmlBlobCSX);
				m_xmlStreamType = TypeOfXmlData.BlobWithText;
				break;
			}
		}

		internal long GetLength()
		{
			if (m_streamDataLength < 0)
			{
				if (m_xmlStreamType == TypeOfXmlData.BlobWithText)
				{
					if (m_xmlBlobText != null)
					{
						m_streamDataLength = m_xmlBlobText.Length;
					}
					else
					{
						m_streamDataLength = 0L;
					}
				}
				else if (m_xmlStreamType == TypeOfXmlData.Clob)
				{
					m_streamDataLength = m_xmlClob.Length;
				}
				else if (m_xmlStreamType == TypeOfXmlData.Chars)
				{
					m_streamDataLength = m_xmlChars.Length * 2;
				}
				else
				{
					m_streamDataLength = m_xmlStr.Length * 2;
				}
			}
			return m_streamDataLength;
		}

		internal string GetValue()
		{
			if (m_xmlStreamType == TypeOfXmlData.BlobWithText)
			{
				if (m_xmlBlobText != null && m_streamDataLength < 1073741823)
				{
					return m_xmlBlobText.ToString();
				}
				return m_xmlBlobText.ToString(0, 1073741822);
			}
			if (m_xmlStreamType == TypeOfXmlData.Clob)
			{
				return m_xmlClob.Value;
			}
			if (m_xmlStreamType == TypeOfXmlData.Chars)
			{
				return new string(m_xmlChars);
			}
			return m_xmlStr;
		}

		internal int Read(char[] buffer, int offset, int count, ref long position)
		{
			long num = 0L;
			if (m_xmlStreamType == TypeOfXmlData.Clob)
			{
				m_xmlClob.Position = position;
				num = m_xmlClob.Read(buffer, offset, count);
				position = m_xmlClob.Position;
			}
			else
			{
				long num2 = 0L;
				num2 = ((position > 0) ? (position / 2) : 0);
				num = ((count + offset > buffer.Length) ? (buffer.Length - offset) : count);
				long length = GetLength();
				long num3 = num * 2;
				if (position + num3 > length)
				{
					num = (length - position) / 2;
				}
				if (num == 0L)
				{
					return 0;
				}
				if (m_xmlStreamType == TypeOfXmlData.Chars)
				{
					Array.Copy(m_xmlChars, num2, buffer, offset, num);
				}
				else if (m_xmlStreamType == TypeOfXmlData.BlobWithText)
				{
					Array.Copy(m_xmlBlobText.ToString((int)num2, (int)num).ToCharArray(), 0L, buffer, offset, num);
				}
				else
				{
					Array.Copy(m_xmlStr.Substring((int)num2, (int)num).ToCharArray(), 0L, buffer, offset, num);
				}
				position += num * 2;
			}
			return (int)num;
		}

		internal int Read(byte[] buffer, int offset, int count, ref long position)
		{
			int num = 0;
			if (m_xmlStreamType != TypeOfXmlData.Clob)
			{
				num = ((m_xmlStreamType != TypeOfXmlData.BlobWithText) ? ReadFromStringValue(buffer, offset, count, ref position) : ReadFromStringBuilder(buffer, offset, count, ref position));
			}
			else
			{
				m_xmlClob.Position = position;
				num = m_xmlClob.Read(buffer, offset, count);
				position = m_xmlClob.Position;
			}
			return num;
		}

		private int ReadFromStringBuilder(byte[] buffer, int offset, int count, ref long position)
		{
			int num = 0;
			new UnicodeEncoding();
			if (position + count > m_xmlBlobText.Length * 2)
			{
				count = m_xmlBlobText.Length * 2 - (int)position;
			}
			if (offset + count > buffer.Length)
			{
				count = buffer.Length - offset;
			}
			if (count <= 0 || offset < 0 || position < 0)
			{
				throw new ArgumentOutOfRangeException("offset or count");
			}
			bool flag = count % 2 > 0;
			bool num2 = position % 2 > 0;
			int num3 = 0;
			int num4 = 0;
			if (num2)
			{
				num = 1;
				num3 = ((int)position - 1) / 2;
				num4 = ((!flag) ? (count / 2) : ((count + 1) / 2));
			}
			else
			{
				num = 0;
				num3 = (int)position / 2;
				num4 = ((!flag) ? (count / 2) : ((count + 1) / 2));
			}
			Buffer.BlockCopy(m_xmlBlobText.ToString(num3, num4).ToCharArray(), num, buffer, offset, count);
			position += count;
			return count;
		}

		private int ReadFromStringValue(byte[] buffer, int offset, int count, ref long position)
		{
			long num = 0L;
			int num2 = count;
			int num3 = offset;
			num = ((position >= 0) ? (position / 2) : 0);
			bool flag = false;
			if (position > 0 && position % 2 != 0L)
			{
				flag = true;
			}
			if (flag)
			{
				if (m_oddByteValue >= 0)
				{
					buffer[num3] = (byte)m_oddByteValue;
					num3++;
					position++;
				}
				else
				{
					ReadByte((int)num);
					buffer[num3] = (byte)m_oddByteValue;
					num3++;
					position++;
				}
				num2--;
				num++;
				if (num2 == 0)
				{
					return 1;
				}
			}
			long num4 = 0L;
			long num5 = 0L;
			long length = GetLength();
			if (num2 == 1)
			{
				if (position < length)
				{
					int num6 = ReadByte((int)num);
					buffer[num3] = (byte)num6;
					num3++;
					position++;
					return 1;
				}
				num4 = 0L;
			}
			else
			{
				num4 = ((num2 + num3 > buffer.Length) ? ((buffer.Length - num3) / 2) : (num2 / 2));
				num5 = num4 * 2;
				if (position + num5 > length)
				{
					num4 = (length - position) / 2;
				}
			}
			if (num4 == 0L)
			{
				return 0;
			}
			Encoding unicode = Encoding.Unicode;
			if (m_xmlStreamType == TypeOfXmlData.Chars)
			{
				unicode.GetBytes(m_xmlChars, (int)num, (int)num4, buffer, num3);
			}
			else
			{
				unicode.GetBytes(m_xmlStr, (int)num, (int)num4, buffer, num3);
			}
			num5 = num4 * 2;
			position += num5;
			if (flag)
			{
				num5++;
			}
			return (int)num5;
		}

		private int ReadByte(int charOffset)
		{
			byte[] array = new byte[2];
			Encoding unicode = Encoding.Unicode;
			if (m_xmlStreamType == TypeOfXmlData.Chars)
			{
				unicode.GetBytes(m_xmlChars, charOffset, 1, array, 0);
			}
			else
			{
				unicode.GetBytes(m_xmlStr, charOffset, 1, array, 0);
			}
			m_oddByteValue = array[1];
			return array[0];
		}

		internal void Dispose()
		{
			m_xmlStr = null;
			m_xmlChars = null;
			if (m_xmlBlobText != null)
			{
				m_xmlBlobText.Clear();
				m_xmlBlobText = null;
			}
			if (m_xmlClob != null)
			{
				m_xmlClob.Dispose();
			}
			m_oddByteValue = -1;
			m_connImpl = null;
			m_xmlTypeData = null;
			m_xmlStreamType = TypeOfXmlData.String;
			m_bInitialized = false;
		}
	}
}
